package se.webbzon.oschi01.gui;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;

import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import se.webbzon.oschi01.nbt.Tag;
import se.webbzon.oschi01.nbt.TagEvent;
import se.webbzon.oschi01.nbt.TagEvent.Action;
import se.webbzon.oschi01.nbt.TagListener;

public class NBTTreeModel implements TreeModel {
	
	private final TagListenerImpl tagListener;
	private final Collection<TreeModelListener> treeModelListeners;
	private final Tag<?> root;
	
	public NBTTreeModel(Tag<?> root) {
		tagListener = new TagListenerImpl();
		treeModelListeners = new ArrayList<TreeModelListener>();
		this.root = root;
	}

	@Override public Object getRoot() {
		return root;
	}

	@Override public Object getChild(Object parent, int index) {
		return ((Tag<?>) parent).getChildren().getSibling(index);
	}

	@Override public int getChildCount(Object parent) {
		return ((Tag<?>) parent).getChildren().siblings();
	}

	@Override public boolean isLeaf(Object node) {
		return !((Tag<?>) node).hasChildren();
	}

	@Override public void valueForPathChanged(TreePath path, Object newValue) {
		
	}

	@Override public int getIndexOfChild(Object parent, Object child) {
		Tag<?> tag = (Tag<?>) parent;
		if (tag.hasChildren()) {
			int i = 0;
			for (Tag<?> c : tag.getChildren()) {
				if (c.equals(child))
					return i;
				else
					i++;
			}
		}
		return -1;
	}

	@Override public void addTreeModelListener(TreeModelListener l) {
		if (treeModelListeners.isEmpty() && root != null) {
			root.addListener(tagListener);
		}
		treeModelListeners.add(l);
	}

	@Override public void removeTreeModelListener(TreeModelListener l) {
		treeModelListeners.remove(l);
		if (treeModelListeners.isEmpty() && root != null) {
			root.removeListener(tagListener);
		}
	}
	
	private final class TagListenerImpl implements TagListener {

		@Override public void onTagEvent(TagEvent e) {
			ArrayDeque<Tag<?>> path = new ArrayDeque<Tag<?>>();
			Tag<?> tag = e.source();
			path.push(tag);
			while (tag.hasParent()) {
				tag = tag.getParent();
				path.push(tag);
			} 
			TreeModelEvent tme;
			int[] indicies = e.indicies();
			if (indicies.length > 0 && indicies[0] > -1) {
				tme = new TreeModelEvent(NBTTreeModel.this,path.toArray(),indicies,e.values());
			} else
				tme = new TreeModelEvent(NBTTreeModel.this,path.toArray());
			TreeModelListener[] type = new TreeModelListener[0];
			
			Action a = e.getAction();
			if (a == Action.CHANGED || a == Action.RENAMED) {
				for (TreeModelListener listener : treeModelListeners.toArray(type)) {
					listener.treeNodesChanged(tme);
				}
			} else if (a == Action.CHILD_ADDED) {
				for (TreeModelListener listener : treeModelListeners.toArray(type)) {
					listener.treeNodesInserted(tme);
				}
			} else if (a == Action.CHILD_REMOVED) {
				for (TreeModelListener listener : treeModelListeners.toArray(type)) {
					listener.treeNodesRemoved(tme);
				}
			}
		}
		
	}

}
